/*
<license>
Copyright (c) 2008, Chris Venter <chris.venter@gmail.com>
All rights reserved.

This file is part of quicktag <http://code.google.com/p/quicktag/>

quicktag is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

quicktag is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this code.
If not, see <http://www.gnu.org/licenses/>.
</license>
*/
#ifndef QUICKTAG_READER_H
#define QUICKTAG_READER_H
 
/** \file reader.h
\todo documentation!
*/

#include "quicktag.h"

#include <string>
#include <list>
#include <map>

#include <generik/stringutils.h>
#include <generik/osutils.h>

namespace quicktag
{

	struct track_type
	{
		std::string nr;
		std::string title;
		std::string file;
		std::string genre;
		track_type(
			const std::string& nr_in,
			const std::string& title_in,
			const std::string& file_in,
			const std::string& genre_in
			)
		: nr(nr_in)
		, title(title_in)
		, file(file_in)
		, genre(genre_in)
		{}
	};
	struct album_type
	{
		std::list<track_type> tracks;
	};
	struct artist_type
	{
		std::map<std::string, album_type> albums;
	};
	struct artist_map
	{
		std::map<std::string, artist_type> artists;
	};
	
	/** 
	\todo documentation!
	*/
	struct reader
	{

		artist_map all;
		std::list<std::string> unhandled_files;
		std::list<std::string> failed_files;
	
		void process(const std::string& path, quicktag::tags tags)
		{
			generik::pathparts pathparts1(path);
			generik::pathparts pathparts2(pathparts1.directory);
			generik::pathparts pathparts3(pathparts2.directory);
			
			if (tags.artist.empty())
			{
				if (!pathparts3.filename.empty())
					tags.artist = pathparts3.filename + generik::pathseperator();
			}
			if (tags.album.empty())
			{
				if (!pathparts2.filename.empty())
					tags.album = pathparts2.filename + generik::pathseperator();
			}
			if (tags.title.empty())
			{
				if (!pathparts2.filename.empty())
					tags.title = pathparts1.fullfile();
			}
		
			artist_type& artist = all.artists[tags.artist];
			album_type& album = artist.albums[tags.album];
			album.tracks.push_back(track_type(tags.tracknr, tags.title, path, tags.genre));
		}

		void process_path(const std::string& path)
		{
			GENERIK_TRACER;
			
			// need to distinguish between "could not process" and "error during processing"
			// solution: "could not process" is return false
			// "error during processing" is silent return true (so that processing stops for this file)
			//    but the path is pushed into failed_files.
			// therefore the NNN_Tag_Read_File_Tag() functions need to return 
			//     TAG_READ_OK, TAG_READ_NOTAGS and TAG_READ_FAIL
			// in the process_NNN functions - they need to make the decision!
			
			quicktag::tags tags;
			tags.init();
		
			int result = quicktag::read_file(path, tags);
			if (result == READVAL_OK)
			{
				GENERIK_TRACE("processing ["<<path<<"]");
				process(path, tags);
			}
			else if (result == READVAL_UNKNOWN)
			{
				GENERIK_TRACE("unhandled ["<<path<<"]");
				unhandled_files.push_back(path);
			}
			else
			{
				// check tags.isok() and tags.error() to determine what went wrong...
				GENERIK_TRACE("failed ["<<path<<"]");
				failed_files.push_back(path);
			}
		}
	
		typedef void(*hook_callback)(int, int, const std::string&, void*);

		reader(const std::list<std::string>& files, hook_callback hc, void* object)
		{
			GENERIK_TRACER;
			
			all.artists.clear();
			unhandled_files.clear();
			failed_files.clear();
			
			int count = 0;
			int total = files.size();
			for (std::list<std::string>::const_iterator i = files.begin(); i != files.end(); ++i)
			{
				if (hc) (*hc)(count, total, *i, object);
				count++;
				process_path(*i);
			}
			if (hc) (*hc)(total, total, "", object);
		}
		
		artist_map& results()
		{
			return all;
		}
	};

}


#endif







